<?php

namespace plugins\yifang_install\db;

use app\utils\encrypt\Hash_pbkdf2;

class D_install
{
    /**
     * 汇报数据
     */
    public function reportData()
    {
        $url=config("app.url","");
        $cmsSiteUrl=config("app.cmsSiteUrl","");
        $data=array();
        $data["domain"]=$url;
        $submitUrl="{$cmsSiteUrl}/api/yifang_receive_data/installDomain";
        $paramsObj = paramsObj();
        $paramsObj->params = array(
            "data" => $data,
            "submitUrl" => $submitUrl,
            "method" => "post",
        );
        app("P_http")->send($paramsObj);
    }

    /**
     * 上报错误
     */
    public function reportLog($errorMsg,$data=array())
    {
		$cmsSiteUrl=config("app.cmsSiteUrl","");
        $params=array();
        $params["error_msg"]=$errorMsg;
        $params["data"]=$data;
        $submitUrl="{$cmsSiteUrl}/api/yifang_receive_data/installLog";
        $paramsObj = paramsObj();
        $paramsObj->params = array(
            "data" => $params,
            "submitUrl" => $submitUrl,
            "method" => "post",
        );
        app("P_http")->send($paramsObj);
    }

    /**
     * 初始化数据
     */
    public function initData()
    {
        $this->addFriend();
        app("YifangBackendAccount_L_install")->recordRbacPermissionCode();
    }

    /**
     * 添加默认友链
     */
    public function addFriend(){
        $linkname=data("cms.info.web_name","龙腾CMS");
		$linkUrl=config("app.cmsSiteUrl","");
        $paramsObj=paramsObj();
        $paramsObj->params=array(
            'linkName' => $linkname,
            'verify' => '0',
        );
        $checkResult=app("S_Admin_friendLink")->infoByLinkName($paramsObj);
        if($checkResult["error_no"]=="0"){
            $result=$checkResult["result"];
            if(!$result){
                $paramsObj=paramsObj();
                $paramsObj->params=array(
                    'status' => '1',
                    'linkName' => $linkname,
                    'linkUrl' => $linkUrl,
                    'className' => '#000000',
                );
                $checkResult=app("S_Admin_friendLink")->store($paramsObj);
                if($checkResult["error_no"]){
                    return false;
                }
            }
        }else{
            return false;
        }
        return true;
    }

    /**
     * 获取用户协议
     */
    public function getUserAgreement(){
        $agreement="我是用户协议";
        return $agreement;
    }

    /**
     * 获取环境数据
     */
    public function getEnv(){
        $gd_info=function_exists("gd_info")?gd_info():array();

        $php_version=explode(".",phpversion());
        $allowPhpVersion=array(
            7,0,0
        );
        $php_pass=$this->compareVersions($php_version,$allowPhpVersion);

        $openssl_pass=$this->phpinfoMap("openssl")?true:false;
        $json_pass=$this->phpinfoMap("json")?true:false;
        $gd_pass=$gd_info?true:false;
        $mysql_pass=true;

        $data=array();
        $data["mysql"]="支持";
        $data["mysql_pass"]=$mysql_pass;

        $data["php_version"]=phpversion();
        $data["php_pass"]=$php_pass;

        $data["openssl"]=$openssl_pass?"支持":"不支持";
        $data["openssl_pass"]=$openssl_pass;

        $data["json"]=$json_pass?"支持":"不支持";
        $data["json_pass"]=$json_pass;

        $data["gd"]=$gd_pass?$this->getGdFormat($gd_info):"不支持";
        $data["gd_pass"]=$gd_pass;
        $data["pass"]=($mysql_pass && $php_pass && $openssl_pass && $json_pass && $gd_pass)?true:false;
        return $data;
    }

    /**
     * 比较php版本是否满足条件
     * @param $gd_info
     * @return string
     */
    public function compareVersions($form,$to){
        $result=true;
        if($form && $to){
            foreach($form as $key=>$val){
                if(!(isset($to[$key]) && $val>=$to[$key])){
                    $result=false;
                    break;
                }
            }
        }
        return $result;
    }

    /**
     * 检测文件/目录
     */
    public function getFileStatus(){
        $filePass=true;
        $file=array(
            "runtime/"=>YIFANG_ROOT."/runtime",
            "upload/"=>YIFANG_ROOT."/public/upload",
        );

        $result=array();
        $data=array();
        foreach($file as $key=>$val){
            if(file_exists($val)){
                if (isWritable($val)) {
                    $data[]=array(
                        "name"=>$key,
                        "result"=>true,
                    );
                } else {
                    $data[]=array(
                        "name"=>$key,
                        "result"=>false,
                    );
                    $filePass=false;
                }
            }else{
                $data[]=array(
                    "name"=>$key,
                    "result"=>false,
                );
                $filePass=false;
            }
        }
        $result["data"]=$data;
        $result["pass"]=$filePass;
        return $result;
    }

    /**
     * 获取数据库填写信息
     */
    public function getDbInput(){
        return session()->get("isDb",array());
    }

    /**
     * 获取管理账号填写信息
     */
    public function getAdminInput(){
        return session()->get("isAdmin",array());
    }

    /**
     * 获取当前访问host
     */
    public function getHost(){
        $data=array();
        $data["host"]=request()->domain();
        return $data;
    }

    /**
     * 获取当前访问host
     */
    public function sessionDel(){
        //清除session
        session()->clear();
    }

    /**
     * 数据库检测
     */
    public function dbCheck(){
        $db_host=trim(request()->param("db_host",""));
        $db_user=trim(request()->param("db_user",""));
        $db_pwd=trim(request()->param("db_pwd",""));
        $db_name=trim(request()->param("db_name",""));
        $db_table_pre=trim(request()->param("db_table_pre",""));
        $force_install=trim(request()->param("force_install",""));

        $data=array();
        $data["db_host"]=$db_host;
        $data["db_user"]=$db_user;
        $data["db_pwd"]=$db_pwd;
        $data["db_name"]=$db_name;
        $data["db_table_pre"]=$db_table_pre;
        session()->set("isDb",$data);

        if(!$db_host){
            return $this->apiResult(false,"请填写数据库地址",1);
        }
        if(!$db_user){
            return $this->apiResult(false,"请填写数据库用户",1);
        }
        if(!$db_pwd){
            return $this->apiResult(false,"请填写数据库密码",1);
        }
        if(!$db_name){
            return $this->apiResult(false,"请填写数据库名称",1);
        }

        try{
            $connect=$this->getConnect($db_host,$db_user,$db_pwd);
            $connect->connect();
            $dbSql="show databases;";
            $dbResult=$connect->execute($dbSql);
            if($dbResult){
                $dbs=array_column($dbResult,"Database");
                if(in_array($db_name,$dbs) && !$force_install){
                    return $this->apiResult(false,"当前创建的数据库已存在,继续执行数据库将被覆盖。",1);
                }
            }
        }catch (\Throwable $e){
            return $this->apiResult(false,"数据库链接失败",1);
        }
        return $this->apiResult(true,"success",0);
    }

    /**
     * 错误响应
     * @return array
     */
    public function error(){
        return $this->apiResult(false,"安装失败",1);
    }

    /**
     * 目录删除
     * @param $dir
     * @return bool
     */
    public function dirDelete($dir) {
        $dir = dirFormat($dir);
        if(!is_dir($dir)) return false;
        $list = glob($dir.'*');
        if($list) {
            foreach($list as $v) {
                if(!in_array($v,array(".",".."))){
                    is_dir($v) ? $this->dirDelete($v) : @unlink($v);
                }
            }
        }
        return @rmdir($dir);
    }

    /**
     * 删除安装文件
     */
    public function delFile(){
        $delData=array();
        $delData[]=YIFANG_ROOT."/plugins/yifang_install";
        if($delData){
            foreach($delData as $file){
                if(is_file($file)){
                    @unlink($file);
                }else if(is_dir($file)){
                    $this->dirDelete($file);
                }
            }
        }
    }

    /**
     * 生成安装文件
     */
    public function installSuccessFile(){
        $installedFile=YIFANG_ROOT."/plugins/yifang_install/installed";
        if(!is_file($installedFile)){
           file_put_contents($installedFile,"install success");
        }
    }

    /**
     * 删除加载标识
     */
    public function deleteLoad(){
        $installedFile=YIFANG_ROOT."/plugins/yifang_install/load";
        if(is_file($installedFile)){
            @unlink($installedFile);
        }
    }

    /**
     * 获取安装信息
     */
    public function getInfo(){
        $adminData=$this->getAdminInput();
        $data=array();
        $data["siteUrl"]=request()->domain();
        $data["adminUrl"]=request()->domain()."/admin";
        $data["userName"]=$adminData["userName"];
        $data["userPwd"]=$adminData["userPwd"];
        return $data;
    }

    /**
     * 链接数据库
     */
    public function connectDb($db_host,$db_name,$db_user,$db_pwd,$tb_pre){
        $connect=config("database.connect");
        $name="database.{$connect}.tb_pre";
        config()->set($name,$tb_pre);

        $type='\app\utils\db\Custom_connection';
        $config=array(
            'type'        => $type,
            'query'        => '\app\utils\db\Custom_query',
            'builder'        => '\yifang\db\builder\Mysql',
            // 服务器地址
            'hostname'    => $db_host,
            // 数据库名
            'database'    =>$db_name,
            // 数据库用户名
            'username'    => $db_user,
            // 数据库密码
            'password'    => $db_pwd,
            // 数据库连接端口
            'hostport'    => '3306',
            // 数据库连接参数
            'params'      => [],
            // 数据库编码默认采用utf8
            'charset'     => 'utf8mb4',
            // 数据库表前缀
            'prefix'      => $tb_pre,
        );
        Db()->connectConfig("mysql",$type,$config);
    }

    /**
     * 获取链接对象
     * @param $db_host
     * @param $db_user
     * @param $db_pwd
     * @return mixed
     */
    public function getConnect($db_host,$db_user,$db_pwd){
        $type='\app\utils\db\Custom_connection';
        $config=array(
            'type'        => $type,
            'query'        => '\app\utils\db\Custom_query',
            'builder'        => '\yifang\db\builder\Mysql',
            // 服务器地址
            'hostname'    => $db_host,
            // 数据库用户名
            'username'    => $db_user,
            // 数据库密码
            'password'    => $db_pwd,
            // 数据库连接端口
            'hostport'    => '3306',
            // 数据库连接参数
            'params'      => [
                \PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY => true,
            ],
            // 数据库编码默认采用utf8
            'charset'     => 'utf8mb4',
            // 数据库表前缀
            'prefix'      => "",
        );
        return Db()->getConnection($config);
    }

    /**
     * 安装
     */
    public function install(){
        $userName=request()->param("userName","");
        $userPwd=request()->param("userPwd","");
        $email=request()->param("email","");
        $url=request()->param("url","");

        $data=array();
        $data["userName"]=$userName;
        $data["userPwd"]=$userPwd;
        $data["email"]=$email;
        $data["url"]=$url;
        session()->set("isAdmin",$data);

        if(!$userName){
            return $this->apiResult(false,"请填写超级管理员名",1);
        }
        if(!$userPwd){
            return $this->apiResult(false,"请填写超级管理员密码",1);
        }
        if(!$email){
            return $this->apiResult(false,"请填写超级管理员邮件",1);
        }
        if(!$url){
            return $this->apiResult(false,"请填写网站访问地址",1);
        }

        $step=array(
            "1"=>"数据库连接",
            "2"=>"创建数据库",
            "3"=>"创建数据表",
            "4"=>"设置管理员",
            "5"=>"获取安全key",
            "6"=>"生成.env",
        );

        $sqlFile=YIFANG_ROOT."/plugins/yifang_install/"."install.sql";
        $menuFile=YIFANG_ROOT."/plugins/yifang_install/"."menu.php";
        $sqlFile=str_replace("\\","/",$sqlFile);
        $envFile=str_replace("\\","/",YIFANG_ROOT."/.env");
        $dbData=$this->getDbInput();
        $db_table_pre=$dbData["db_table_pre"];

        $connect=$this->getConnect($dbData["db_host"],$dbData["db_user"],$dbData["db_pwd"]);

        $conn=null;
        foreach($step as $key=>$val){
            if($key=="1"){
                try{
                    $connect->connect();
                    $connect->execute("set FOREIGN_KEY_CHECKS=0;");
                }catch (\Throwable $e){
                    return $this->apiResult(false,"{$val}失败",1);
                }
            }else if($key=="2"){
                //创建数据库
                $delOk=$connect->execute("DROP DATABASE IF EXISTS `{$dbData["db_name"]}`;");
                $addOk=$connect->execute("CREATE DATABASE `{$dbData["db_name"]}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;");
                if(!($delOk && $addOk)){
                    return $this->apiResult(false,"{$val}失败",1);
                }
            }else if($key=="3"){
                $this->connectDb($dbData["db_host"],$dbData["db_name"],$dbData["db_user"],$dbData["db_pwd"],$dbData["db_table_pre"]);
                //创建数据表
                if(is_file($sqlFile)){
                    $_sql = file_get_contents($sqlFile);
                    $_sql=str_replace("\r","",$_sql);
                    $_arr = explode(";\n", $_sql);
                    foreach($_arr as $sql){
                        $sql=trim($sql);
                        if($sql){
                            $sql=str_replace("{table_pre}",$db_table_pre,$sql);
                            $ok=Db()->execute($sql);
                            if(!$ok){
                                return $this->apiResult(false,"{$val}失败",1);
                            }
                        }
                    }
                }else{
                    return $this->apiResult(false,"{$val}失败",1);
                }

                //录入菜单数据
                if(is_file($menuFile)){
                    //写入后台菜单
                    $menuData=include_once $menuFile;
                    if($menuData){
                        $paramsObj=paramsObj();
                        $paramsObj->params=array(
                            "plugins"=>"yifang@base,yifang_backend_account",
                            "data"=>$menuData,
                        );
                        $checkResult=app("YifangBackendAccount_L_Admin_rbacNode")->import($paramsObj);
                        if($checkResult["error_no"]=="0"){

                        }else{
                            return $this->apiResult(false,$checkResult["error_msg"],1);
                        }
                    }
                }
            }else if($key=="4"){
                //设置管理员
                $paramsObj=paramsObj();
                $paramsObj->params=array(
                    'account' => $userName,
                    'pwd' => $userPwd,
                    'is_supper' => '1',
                    'status' => '1',
                );
                $checkResult=app("YifangBackendAccount_L_Admin_rbacAdmin")->store($paramsObj);
                if ($checkResult["error_no"] == 0) {

                }else{
                    return $this->apiResult(false,"{$val}失败",1);
                }
            }else if($key=="5"){
                //获取安全key | rsa 加密
                $signatureData=array();
                $ok=true;
                if($ok===false){
                    return $this->apiResult(false,"{$val}失败",1);
                }
            }else if($key=="6"){
                //生成.env
                $envStr=<<<ENV
[APP]                
url={$url}    
secretId=7583a634cfa23f6b8c63b3ca5e92e901
secretKey=f5b3757f31e5e00ae0c1853fef46d68e
            
[MYSQL]
db_host={$dbData["db_host"]}
db_name={$dbData["db_name"]}
db_user={$dbData["db_user"]}
db_pwd={$dbData["db_pwd"]}
tb_pre={$dbData["db_table_pre"]}
ENV;
                $ok=file_put_contents($envFile,$envStr);
                if($ok===false){
                    return $this->apiResult(false,"{$val}失败",1);
                }
            }
        }
        return $this->apiResult(true,"success",0);
    }

    /*
     * api返回信息
     */
    public function apiResult($success=false,$codeMsg="",$code=1,$data=null,$extra=null)
    {
        $success=(bool) $success;
        $code=intval($code);
        $codeMsg=(string) $codeMsg;
        if(is_null($extra)){
            $extra=new \ArrayObject();
        }
        if(is_null($data)){
            $data=new \ArrayObject();
        }
        $map=array(
            "success"=>$success,
            "code"=>$code,
            "codeMsg"=>$codeMsg,
            "data"=>$data,
            "extra"=>$extra,
        );
        return $map;
    }

    /**
     * @param $dir
     * @return bool
     */
    public function is_writable_r($dir){
        if(!is_dir($dir)){
            return false;
        }
        $children = scandir($dir);
        foreach($children as $child){
            if($child != '.' && $child != '..'){
                $child_path = $dir . "/" . $child;
                if(is_dir($child_path)){
                    if(!$this->is_writable_r($child_path)){
                        return false;
                    }
                }elseif(!is_writable($child_path)){
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 获取 gb 格式
     * @param $gd_info
     * @return string
     */
    public function getGdFormat($gd_info){
        $data=array();
        if($gd_info){
            foreach($gd_info as $key=>$val){
                if($key=="JPEG Support" && $val){
                    $data[]="jpg";
                }else if($key=="PNG Support" && $val){
                    $data[]="png";
                }else if($key=="GIF Read Support" && $val){
                    $data[]="gif";
                }else if($key=="JPEG Support" && $val){
                    $data[]="jpeg";
                }
            }
        }
        return $data?implode(" ",$data):"";
    }

    /**
     * 获取php信息
     * @return array
     */
    public function phpinfoMap($key=null)
    {
        ob_start();
        phpinfo();
        $info_arr = array();
        $info_lines = explode("\n", strip_tags(ob_get_clean(), "<tr><td><h2>"));
        $cat = "General";
        foreach($info_lines as $line)
        {
            // new cat?
            preg_match("~<h2>(.*)</h2>~", $line, $title) ? $cat = $title[1] : null;
            if(preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val))
            {
                $info_arr[$cat][$val[1]] = $val[2];
            }
            elseif(preg_match("~<tr><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td><td[^>]+>([^<]*)</td></tr>~", $line, $val))
            {
                $info_arr[$cat][$val[1]] = array("local" => $val[2], "master" => $val[3]);
            }
        }
        if($key){
            return isset($info_arr[$key])?$info_arr[$key]:"";
        }else{
            return $info_arr;
        }
    }

    public function __call($name,$arguments)
    {
        return recordLogMsgLevelTwo(app("errorLevel")::E_WARNING,app("errorCode")::UNDEFINED_METHOD,lang("sys.noMethodDefined"),$name,$arguments);
    }
}